/*****************************************************************************/
/*!	\file			IEC61850API.h
 *	\brief 		IEC61850 API header file
	\par        Dalian Yunxing Tech Co., Ltd.

				Dalian, China
				Phone   : +86 (411) 8825 4852
				Email   : yx@yunxing.tech
 */
/*****************************************************************************/

/******************************************************************************
*	Defines
******************************************************************************/

#ifndef IEC61850_INCLUDED
#define IEC61850_INCLUDED 1

#include "sysctype.h"
#include "IEC61850Types.h"

/*!	\brief PIS10 Version Number */ 
#define PIS10_VERSION         "V2.09.04.12"

/*
Library Control complier options

In a windows environment

	if PIS10_STATIC is defined then the library will be complied for static linking

	For making a DLL define PIS10_EXPORTS
	For using the DLL no NOT define PIS10_EXPORTS
*/

#if defined(WIN32) || defined(WIN64)
	#ifdef PIS10_STATIC
		#define PIS10_API
	#else
		#if defined(PIS10_EXPORTS) || defined(DLL_EXPORT)
			#define PIS10_API __declspec(dllexport)
		#else
			#define PIS10_API __declspec(dllimport)
		#endif
	#endif
#else
	/*!API function prefix  */
	#define PIS10_API
#endif

/*!

\defgroup 	DataAttributeAccess 	Data Attribute Access functions
\defgroup 	Management 				IEC61850 Object management functions
\defgroup 	Time 					Time functions
\defgroup 	Support 				Support functions
\defgroup 	Control 				Control functions
\defgroup 	FileTransfer 			File Transfer functions
\defgroup	TimeConversion			Time conversion functions

 */


#ifdef __cplusplus
extern "C" {
#endif
/*! \brief 	Create a client or server object with call-backs for reading, writing and updating data objects
	\ingroup 	Management

	\param[in] 	ptParameters  	IEC 61850 Object Parameters
	\param[out] 	peErrorCode  	pointer to return enum #IEC61850_ErrorCodes for error code if an error occurred or #IEC61850_ERROR_NONE on success 

	\return 	Pointer to a new IEC 61850 object
	\return 	NULL if an error occurred (errorCode will contain an error code)

	\see IEC61850_Free()

	Server example usage:
	\code
		// Create Server
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
		IEC61850 myServer = NULL;
		struct IEC61850_Parameters	tServerParam = {0}; //Structure memory must be initialised to 0

		memset(&tServerParam, 0, sizeof(struct IEC61850_Parameters));

		tServerParam.ClientServerFlag 	= IEC61850_SERVER;		// This is a IEC 61850 Server
		tServerParam.Ed1_Ed2_Flag		 =IEC61850_Edition2; 	// Set the IEC61850 Edition
		tServerParam.uiOptions			= IEC61850_OPTION_NONE;	// No options set
		tServerParam.uiCmdTermTimeOut	= 0;						// Command Termination timeout 0 will default to 10 seconds
		tServerParam.ptReadCallback 	= ReadFunction;			// Assign Read Callback Function
		tServerParam.ptWriteCallback 	= WriteFunction;			// Assign Write Callback Function
		tServerParam.ptUpdateCallback 	= NULL;					// No Update Callback Function for Server
		tServerParam.ptSelectCallback	= NULL;					// Ignoring Select commands
		tServerParam.ptOprTestCallback 	= OperativeTestFunction; //Mandatory callback in Edition 2 server
		tServerParam.ptOperateCallback	= NULL;					// Ignoring Operate commands
		tServerParam.ptCancelCallback 	= NULL;					// Ignoring Cancel commands


		//Create a server
		myServer = IEC61850_Create(&tServerParam, &error);
		if(myServer == NULL)
		{
			printf("Server Failed to create: %s (%u)", IEC61850_ErrorString(error), error);
		}
	\endcode


	Client example usage:
	\code

		// Create Client
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
		IEC61850 myClient = NULL;
		struct IEC61850_Parameters	tClientParam = {0}; //Structure memory must be initialised to 0

		memset(&tClientParam, 0, sizeof(struct IEC61850_Parameters));

		tClientParam.ClientServerFlag	= IEC61850_CLIENT;			// This is a IEC 61850 Client
		tClientParam.uiOptions			= 0;						// Reserved for future use (set to ZERO)
		tClientParam.iCmdTermTimeOut	= 0;						// Command Termination timeout 0 will default to 10000 milliseconds
		tClientParam.ptReadCallback 	= NULL;						// No Read Callback Function for Client
		tClientParam.ptWriteCallback	= NULL;						// No Update Callback Function for Client
		tClientParam.ptUpdateCallback 	= UpdateFunction;			// Assign Update Callback Function for Client
		tClientParam.ptSelectCallback	= NULL;					// Ignoring Select commands
		tClientParam.ptOperateCallback	= NULL;					// Ignoring Operate commands
		tClientParam.ptCancelCallback 	= NULL;					// Ignoring Cancel commands

		//Create a client
		myClient = IEC61850_Create(&tClientParam, &error);
		if(myClient == NULL)
		{
			printf("Client Failed to create: %s (%u)", IEC61850_ErrorString(error), error);
		}
	\endcode
 */
PIS10_API IEC61850 IEC61850_Create(struct IEC61850_Parameters * ptParameters, enum IEC61850_ErrorCodes * peErrorCode);

/*!  \brief 		Free memory allocated to IEC61850 object.
	\ingroup 	Management

	 \param[in] 	clientServerObject	  		Server/Client object to free

	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	\see IEC61850_Create()

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;

		error = IEC61850_Free(myServer);  //Frees myServer
		if(error != IEC61850_ERROR_NONE)
		{
			printf("Free IEC61850 Object has failed: %s (%u)", IEC61850_ErrorString(error), error);
		}
	\endcode
 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_Free(IEC61850 clientServerObject);

/*!  \brief 	Load a SCL file into the given IEC61850 object
	\ingroup 	Management

	 \param[in] 	clientServer	client/Server object
	 \param[in] 	SCLFileName		File name of the SCL file

	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;

		error = IEC61850_LoadSCLFile(myServer,"myIED.cid"); // Load in IED configuration SCL file
		if(error != IEC61850_ERROR_NONE)
		{
			printf("Loading SCL file has failed: %s (%u)", IEC61850_ErrorString(error), error);
		}
	\endcode

 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_LoadSCLFile(IEC61850 clientServer, const char * SCLFileName);

/*!	\brief 	Start IEC61850 object communications
	\ingroup 	Management

	\param 		clientServer		client or Server object to start

	\return 	#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	\see IEC61850_Stop()

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;

		error = IEC61850_Start(myServer); // Starts myServer
		if(error != IEC61850_ERROR_NONE)
		{
			printf("Can't start server: %s (%u)", IEC61850_ErrorString(error), error);
		}
	\endcode
 */
PIS10_API enum IEC61850_ErrorCodes  IEC61850_Start(IEC61850 clientServer);

/*! \brief 	Stop IEC61850 object communications
	\ingroup 	Management

	\param 	clientServer			client or Server object to stop

	\return 	#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	\see IEC61850_Start()

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;

		error = IEC61850_Stop(myServer); // Stops myServer
		if(error != IEC61850_ERROR_NONE)
		{
			printf("Can't stop server: %s (%u)", IEC61850_ErrorString(error), error);
		}
	\endcode

 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_Stop(IEC61850 clientServer);

/*!  \brief 		Update a given Object(s) of tObjectID with value of ptNewValue , up to 128 objects can be updated from one call
	\ingroup 	DataAttributeAccess

	 \param[in] 	server			Server object to update
	 \param[in] 	ptDAID			Array of IEC61850_DataAttributeID structures. This array identifies the points that are to be updated. This array need to be the same length as the ptNewValue array.
	 \param[in] 	ptNewValue		Array of struct IEC61850_DataAttributeData structures. This holds the new value of the object identified in the ptDAID array. This array need to be the same length as the ptDAID array.
	 \param[in] 	uiCount			The number of IEC61850_DataAttributeID and struct IEC61850_DataAttributeData structures in the array pointed to by ptObjectID and ptNewValue respectively, Max value = 128

	\return 	#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
		struct IEC61850_DataAttributeData 	Value;
		struct IEC61850_DataAttributeID_Generic  tObjectID;
		Unsigned32		u32Counter;

		u32Counter = 34;

		// Load Data
		Value.ucType =  IEC61850_DATATYPE_INT32;
		Value.uiBitLength = sizeof(u32Counter)*8;
		Value.iArrayIndex = 0;
		Value.pvData = &u32Counter;

		// Load ID
		memset(&tObjectID, 0, sizeof(tObjectID));
		tObjectID.Generic_type = IEC61850_DAID_GENERIC;
		tObjectID.uiField1  = 1;
		tObjectID.uiField2 = 6;
		tObjectID.uiField3 = 1;
		tObjectID.uiField4 = 0;
		tObjectID.uiField5 = 0;

		error = IEC61850_Update(myServer, (struct IEC61850_DataAttributeID *)&tObjectID, &Value, 1);
		if(error != IEC61850_ERROR_NONE)
		{
			printf("Update failed: %s (%u)", IEC61850_ErrorString(error), error);
		}
	\endcode

 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_Update(IEC61850 server, struct IEC61850_DataAttributeID * ptDAID, const struct IEC61850_DataAttributeData * ptNewValue, unsigned int uiCount);

/*!  \brief 		Read a value to a given Object ID via the client
	 \ingroup 	DataAttributeAccess

	 \param[in] 	client			Client object to read from
	 \param[in] 	ptDAID			Pointer to IEC61850_DataAttributeID structure that identifies the point that is to be read
	 \param[out] 	ptReturnedValue	Pointer to Object Data structure to hold the returned value,
									- uiBitLength must initially be the size in bits of the pvData memory block, it will be changed to the number of bits in the read value
									- pvData pointer must be a valid memory block with enough bytes to hold the value
									

	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
		struct IEC61850_DataAttributeData 	Value;
		struct IEC61850_DataAttributeID_Generic  tObjectID;
		Unsigned32		u32Counter;

		// Load Data
		Value.ucType =  IEC61850_DATATYPE_INT32;
		Value.uiBitLength = sizeof(u32Counter)*8;
		Value.iArrayIndex = 0;
		Value.pvData = &u32Counter;

		// Load ID
		memset(&tObjectID, 0, sizeof(tObjectID));
		tObjectID.Generic_type = IEC61850_DAID_GENERIC;
		tObjectID.uiField1  = 1;
		tObjectID.uiField2 = 6;
		tObjectID.uiField3 = 1;
		tObjectID.uiField4 = 0;
		tObjectID.uiField5 = 0;

		error = IEC61850_Read(myServer, (struct IEC61850_DataAttributeID *)&tObjectID, &Value);
		if(error != IEC61850_ERROR_NONE)
		{
			printf("Read failed: %s (%u)", IEC61850_ErrorString(error), error);
		}
		else
		{
			printf("Count = %u",u32Counter);
		}
	\endcode
 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_UpdateWithSortAddr(IEC61850 server, char** sAddrList, const struct IEC61850_DataAttributeData* ptNewValue, unsigned int uiCount);
PIS10_API enum IEC61850_ErrorCodes IEC61850_Read(IEC61850 client, struct IEC61850_DataAttributeID * ptDAID, struct IEC61850_DataAttributeData * ptReturnedValue);


/*!  \brief 	Write a value to a given Object ID via the client, <br>
				This function will block as it waits for the write response from the server which it will use to determine the returned error code.

	\ingroup 	DataAttributeAccess

	 \param[in] 	client			Client object to write to
	 \param[in] 	ptDAID			Pointer to IEC61850_DataAttributeID structure (or compatible) that identifies the point that is to be written
	 \param[in] 	ptNewValue		Pointer to Object Data structure that hold the new value of the tObjectID

	 \return 	#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
		struct IEC61850_DataAttributeData 	Value;
		struct IEC61850_DataAttributeID_Generic  tObjectID;

		char		bFlag;

		bFlag = 1; // Set flag equal to True

		// Load Data
		Value.ucType =  IEC61850_DATATYPE_BOOLEAN;
		Value.uiBitLength = sizeof(bFlag)*8;
		Value.iArrayIndex = 0;
		Value.pvData = &bFlag;

		// Load ID
		memset(&tObjectID, 0, sizeof(tObjectID));
		tObjectID.Generic_type = IEC61850_DAID_GENERIC;
		tObjectID.uiField1  = 1;
		tObjectID.uiField2 = 4;
		tObjectID.uiField3 = 1;
		tObjectID.uiField4 = 0;
		tObjectID.uiField5 = 0;

		error = IEC61850_Write(myServer, (struct IEC61850_DataAttributeID *)&tObjectID, &Value);
		if(error != IEC61850_ERROR_NONE)
		{
			printf("Write failed: %s (%u)", IEC61850_ErrorString(error), error);
		}
	\endcode
 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_Write(IEC61850 client, struct IEC61850_DataAttributeID * ptDAID, const struct IEC61850_DataAttributeData * ptNewValue);

/*!  \brief 		Returns a human readable description of a given error code
	 \ingroup 	Support

	 \param[in] 	eErrorCode		Error code in question of type enum #IEC61850_ErrorCodes

	 \return 	pointer to text string explaining error code or NULL on failure 

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;

		printf("Error: %s", IEC61850_ErrorString(error));
	\endcode
 */
PIS10_API const char * IEC61850_ErrorString(enum IEC61850_ErrorCodes eErrorCode);

/*!  \brief 	Returns library version number
	 \ingroup 	Support

	 \return 	version number of library  as a string of char with format A.BC.DE.FGH

	Example Usage:
	\code
		printf("Version number: %s", IEC61850_GetLibraryVersion());
	\endcode
 */
PIS10_API  const char * IEC61850_GetLibraryVersion(void);

/*!  \brief 	Returns library build time
	 \ingroup 	Support

	 \return 	Build time of the library as a string of char. Format "Mmm dd yyyy hh:mm:ss"

	Example Usage:
	\code
		printf("Build Time: %s", IEC61850_GetLibraryBuildTime());
	\endcode
 */
PIS10_API const char * IEC61850_GetLibraryBuildTime(void);


/*!  \brief 		Checks the Device for a valid PIS10 license, This function is not valid on Windows
	\ingroup 		License

	 \return 		#IEC61850_ERROR_NONE on success
	 \return 		#IEC61850_ERROR_LICENCE_INVALID on license failure
	 \return		#IEC61850_ERROR_INVALID_PARAMETERS on windows platforms

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;

		error = IEC61850_CheckLicense();
		if(error != IEC61850_ERROR_NONE)
		{
			printf("IEC61850_CheckLicense has failed: %s", IEC61850_ErrorString(error));
		}
	\endcode
 */
PIS10_API enum IEC61850_ErrorCodes  IEC61850_CheckLicense(void);

/*!  \brief 		Set Time Quality flags used in UTC timestamp
	\ingroup 		Time

	\param[in] 	cLeapSecondKnown					Leap second Flag, Non-zero if the leap second is known, zero if leap second is unknown.
	\param[in] 	cClockFailure							Clock Failure Flag. Non-zero if the clock has failed else zero if clock is functional.
	\param[in] 	cClockNotSynchronized					Clock Not Synchronised Flag. Non-zero if the clock is not synchronized other zero if clock is synchronized.
	\param[in] 	iTimeAccuracyOfFractionsOfSecond		Number of Bits using in faction of seconds part of time stamp (range of 0 to 24). Any value less than 0 mean accuracy is not specified.
	 
	\return 	#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;

		error = IEC61850_SetTimeQuality(1, 0, 1, -1);
		if(error != IEC61850_ERROR_NONE)
		{
			printf("IEC61850_SetTimeQuality has failed: %s", IEC61850_ErrorString(error));
		}
	\endcode
 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_SetTimeQuality(char cLeapSecondKnown, char cClockFailure, char cClockNotSynchronized, int iTimeAccuracyOfFractionsOfSecond);



/*!  \brief 		Get Time Quality flags used in UTC Timestamp
	\ingroup 		Time

	\param[out] 	cLeapSecondKnown					Pointer to char which will be set to Non-zero if the leap second is known. May be NULL if not required.
	\param[out] 	cClockFailure							Pointer to char which will be set to Non-zero if the clock has failed. May be NULL if not required.
	\param[out] 	cClockNotSynchronized					Pointer to char which will be set to Non-zero if the clock is not synchronized. May be NULL if not required.
	\param[out] 	iTimeAccuracyOfFractionsOfSecond		Pointer to integer which will be set to the number of bits of time accuracy used in the fraction of seconds part of time stamp (0 to 24 bits). Any number less than 0 mean accuracy is not specified. May be NULL if not required.
	
	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;

		char cLeapSecondKnown = 0;
		char cClockFailure = 0;
		error = IEC61850_GetTimeQuality(&cLeapSecondKnown, &cClockFailure, NULL, NULL);
		if(error != IEC61850_ERROR_NONE)
		{
			printf("IEC61850_GetTimeQuality has failed: %s", IEC61850_ErrorString(error));
		}
		else
		{
			if(cLeapSecondKnown != 0)
			{
				printf(" Leap second known.");
			}
			else
			{
				printf(" Leap second not known.");
			}

			if(cClockFailure != 0)
			{
				printf(" Clock failed. ");
			}
			else
			{
				printf(" Clock OK.");
			}
		}
	\endcode
 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetTimeQuality(char  * cLeapSecondKnown, char * cClockFailure, char * cClockNotSynchronized, int * iTimeAccuracyOfFractionsOfSecond);

/*!  \brief 		Get the current system time as IEC 61850 Time stamp, if the clientServer parameter is NULL the function will always use the system clock as the time source.
	\ingroup 		Time

	\param[in] 		clientServer		The IEC61850 object of the client or Server (returned by create), or NULL to force the use of the system clock to get time.
	\param[out] 	ptCurrentTime		Pointer to a IEC61850_TimeStamp structure that will be filled with the current time. (With time quality included)

	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	Example Usage:
	\code

	struct IEC61850_TimeStamp  tTime;
	if(IEC61850_GetTime(myServer, &tTime) == IEC61850_ERROR_NONE)
	{
		printf("Seconds: %u Fraction of seconds: %X" tTime.u32Seconds, tTime.u32FractionsOfSecond);
	}


	\endcode
 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetTime( IEC61850 clientServer, struct IEC61850_TimeStamp * ptCurrentTime);

/*!  \brief 		Get Current Time as IEC 61850 Time stamp.
	\ingroup 		Time

	\param[in] 	ptNewTime	New time to set, not including time quality

	 \return 	#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	Note: Only works for BECK 124

	Example Usage:
	\code

	struct IEC61850_TimeStamp  tTime;

	tTime.u32Seconds = 455896518;
	tTime.u32FractionsOfSecond = 0;

	if(IEC61850_SetTime(&tTime) != IEC61850_ERROR_NONE)
	{
		printf("Set Time Faild" );
	}

	\endcode
 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_SetTime(struct IEC61850_TimeStamp * ptNewTime);


/*!  \brief 		Set the user data that will be returned in all callbacks as a parameter <br>
					Using this allows you to access your application data without using global variables<br>
					It is suggested to create a structure with pointers to your data so it can be expanded easily in the future <br>

	 \ingroup 	Support

	 \param[in] 	clientServer		Client/server object to set user data
	 \param[in] 	ptData			Pointer to user data that you want to see when callback called - Ensure this pointer is always valid, recommended to come from the heap (calloc/malloc)

	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	Example usage:
	\code

		IEC61850 myServer; 
		struct myCustomDataStructure * Data;
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;

		Data = calloc(1, sizeof(struct myCustomDataStructure); 

		//populate your Data Structure with your application data needed in the callbacks

		error = IEC61850_SetUserData(myServer, Data);
		if(error != IEC61850_ERROR_NONE)
		{
			printf("Write has failed: %s", IEC61850_ErrorString(error));
		}
	\endcode
*/
PIS10_API enum IEC61850_ErrorCodes IEC61850_SetUserData(IEC61850 clientServer,  void * ptData);


/*!	 \brief 		Get the Data type and size of a given Data Attribute
	 \ingroup 	DataAttributeAccess


	 \param[in] 	clientServer		Client or Server object to search
	 \param[in] 	ptDAID			ID of Data Attribute
	 \param[out] 	ptReturnedType	ucType and uiBitLength will be filled in with the respective type and size of ptDAID. pvData will be null.

	 \return 	#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure
*/
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetType(IEC61850 clientServer, struct IEC61850_DataAttributeID * ptDAID, struct IEC61850_DataAttributeData * ptReturnedType);

PIS10_API enum IEC61850_ErrorCodes IEC61850_ControlSelectWithShortAddr(IEC61850 client, char* sAddr, struct IEC61850_DataAttributeData* ptSelectValue, struct IEC61850_ControlParameters tParam);
PIS10_API enum IEC61850_ErrorCodes IEC61850_ControlOperateWithShortAddr(IEC61850 client, char* sAddr, struct IEC61850_DataAttributeData* ptOperateValue, struct IEC61850_ControlParameters tParam);
PIS10_API enum IEC61850_ErrorCodes IEC61850_ControlCancelWithShortAddr(IEC61850 client, char* sAddr, struct IEC61850_DataAttributeData* ptCancelValue);
PIS10_API enum IEC61850_ErrorCodes IEC61850_ControlSelect(IEC61850 client, struct IEC61850_DataAttributeID* ptControlID, struct IEC61850_DataAttributeData* ptSelectValue, struct IEC61850_ControlParameters tParam);
PIS10_API enum IEC61850_ErrorCodes IEC61850_ControlOperate(IEC61850 client, struct IEC61850_DataAttributeID* ptControlID, struct IEC61850_DataAttributeData* ptOperateValue, struct IEC61850_ControlParameters tParam);
PIS10_API enum IEC61850_ErrorCodes IEC61850_ControlCancel(IEC61850 client, struct IEC61850_DataAttributeID* ptControlID, struct IEC61850_DataAttributeData* ptCancelValue);
/*!	 \brief 	Send Command Termination for given control object, Command Termination will only be sent if given control object was the last to generate a Operate Callback,
 				the callback returned a IEC61850_COMMAND_ERROR_NONE and the command termination timeout has not expired (default 10seconds).

	 \ingroup 	Control
	 \since		V2.06.15

	 \param[in]	server 	Server object containing control
	 \param[in]	ptControlID 	ID of control that is to be canceled, this is the ctlVal of the oper
	 \param[in]	eCmndAddCause 	The enum eCommandAddCause value to send with command termination, as defined in IEC61850-7-2 - 17.5.2.6

	 \return	#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	 Example usage:
	 \code
		 enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
		 struct IEC61850_DataAttributeID_Generic CtrlDAID;
		 enum eCommandAddCause eCmdTermCause = IEC61850_COMMAND_ERROR_ADD_CAUSE_UNKNOWN;

		 // Setup the Data Attribute ID (DAID) Struct - We set this to the CtlVal of the Control
		 CtrlDAID.Generic_type = IEC61850_DAID_GENERIC;
		 CtrlDAID.uiField1 = 1;
		 CtrlDAID.uiField2 = 3;
		 CtrlDAID.uiField3 = 3;
		 CtrlDAID.uiField4 = 7;
		 CtrlDAID.uiField5 = 0;

		 // Set the Command Termination cause, from  enum eCommandAddCause in the API
		 eCmdTermCause = IEC61850_COMMAND_ERROR_NONE;

		 //Call the API to send the Command Termination for the given control
		 eErrorCode =  IEC61850_ControlTerminateCommand(myIEC61850Server, &CtrlDAID, eCmdTermCause);

		 if(eErrorCode == IEC61850_ERROR_NONE)
		 {
			 printf("Manual Command Termination sent Successfully\n");
		 }
		 else
		 {
			printf("Sending Command Termination Failed: %i: %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode));
		 }
	 \endcode
*/
PIS10_API enum IEC61850_ErrorCodes IEC61850_ControlTerminateCommand(IEC61850 server, void * pDAMap, enum eCommandAddCause eCmndAddCause);


/*!	 \brief 	Gets the feedback Data Attribute ID for a given Control Private ID (oper.ctlVal) 
	 \ingroup 	Controls
	 \since		V2.08.41

	 \param[in]		ptIEC61850Server 	Server object containing controls
	 \param[in]		ptControlID			pointer to Data Attribute ID of control val (oper.ctlVal) of the feedback value that you want to find
	 \param[out]	ptFeedbackID 		pointer Data Attribute ID that will hold the private ID of the controls feedback value (stVal usually) 

	 \return	#IEC61850_ERROR_NONE on success or #IEC61850_ERROR_DATA_ATTRIBUTE_ID_NOT_FOUND if no control found for the ptControlID or no ptFeedbackID is set for the control

	 Example Usage:
	 \code
		struct IEC61850_DataAttributeID  ptFeedbackID = { 0 };
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;

		error = IEC61850_GetControlFeedbackID(myIEC61850Server, ptControlID, &ptFeedbackID);
		if (error == IEC61850_ERROR_NONE)
		{
			printf("Feedback ID is");
			IEC61850_PrintDataAttributeID(&ptFeedbackID);
		}
	\endcode
*/
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetControlFeedbackID(IEC61850 ptIEC61850Server, const struct IEC61850_DataAttributeID* ptControlID, struct IEC61850_DataAttributeID* ptFeedbackID);

/*!	 \brief 	Print to stdout the value of the IEC61850_DataAttributeID structure ptDAID
	 \ingroup 	Support
	 \since		V1.36.03

	 \param[in]	ptDAID	#IEC61850_DataAttributeID struct that is to be printed

*/
PIS10_API void IEC61850_PrintDataAttributeID(const struct IEC61850_DataAttributeID * ptDAID);

/*!	 \brief 	Print to stdout the value of the IEC61850_DataAttributeData structure ptValue
	 \ingroup 	Support
	 \since		V1.36.03

	 \param[in]	ptValue 	Data value that is to be printed

*/
PIS10_API void IEC61850_PrintDataAttributeData(const struct IEC61850_DataAttributeData * ptValue);

/*!	 \brief 		Returns a pointer to a memory block containing the status of all servers specified in the CID file
	 \ingroup 	Support
	 \since		V1.36.08

	 \param[in]		inClient 	The IEC61850 object created for the current client by IEC61850_Create() and configured by IEC61850_LoadSCLFile()

	 \return 		pointer to a struct #IEC61850_ServerStatusArray pointer containing the results of each poll - do not call Free on this pointer!!
*/
PIS10_API tServerStatusArray IEC61850_PollServers(IEC61850 inClient);



/*!	\brief		Converts MM/DD/YY HH:MM:SS to actual IEC61850 TimeStamp. Epoch year is assumed at Jan 1 1970 , 00:00:01am. Year must be after epoch.
  	\ingroup	TimeConversion
 	\since		V2.05.19

 	\param[out]	outTimestamp	Pointer to Timestamp structure
    \param[in]	month			current month (1-12)
    \param[in]	day				current day
    \param[in]	year			current year (ie, 2015)
    \param[in]	hour			current hour
    \param[in]	minute			current minute
    \param[in]	second			current seconds
    \param[in]	microseconds	current microseconds

	\return 	#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	Example usage:
	\code
		// Get IEC61850 TimeStamp from Readable Date Time
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
		Unsigned8 month = 7;
		Unsigned8 day = 31;
		Unsigned16 year = 2015;
		Unsigned8 hour = 6;
		Unsigned8 minute = 4;
		Unsigned8 second = 44;
		Unsigned32 microseconds = 0;

		struct IEC61850_TimeStamp  IEC61850Time;

		memset(&IEC61850Time, 0, sizeof(struct IEC61850_TimeStamp));

		//Get IEC61850 Time Stamp from date
		error = IEC61850_GetIEC61850TimeFromDate(&IEC61850Time, month, day, year, hour, minute, second, microseconds);
		if(error != IEC61850_ERROR_NONE)
		{
			printf("Failed to Convert time: %s (%u)", IEC61850_ErrorString(error), error);
		}
		else
		{
			printf(" Seconds since Epoch = %u \n", IEC61850Time.u32Seconds);
		}
	\endcode
*/
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetIEC61850TimeFromDate(struct IEC61850_TimeStamp * outTimestamp, Unsigned8 month, Unsigned8 day, Unsigned16 year, Unsigned8 hour, Unsigned8 minute, Unsigned8 second, Unsigned32 microseconds);


/*! \brief		Converts seconds since epoch to MM/DD/YYYY HH:MM:SS. Epoch year is assumed at Jan 1 1970, 00:00:01am. Year must be after epoch

 	\ingroup 	TimeConversion
	\since		V2.05.19

    \param[out]	outDateTime	Pointer to MyTime structure to hold the data
    \param[in]	inTimestamp	IEC61850 Timestamp that holds the time to convert

	\return		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	Example usage:
	\code
		// Get Readable Date Time
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
		struct IEC61850_DateTime myDateTime;
		struct IEC61850_TimeStamp  IEC61850Time;

		memset(&myDateTime, 0, sizeof(struct IEC61850_DateTime));
		memset(&IEC61850Time, 0, sizeof(struct IEC61850_TimeStamp));

		IEC61850Time.u32Seconds = 1438322683;

		//Get Date from IEC61850 Time Stamp
		error = IEC61850_GetDateFromIEC61850Time(&myDateTime, &IEC61850Time);
		if(error != IEC61850_ERROR_NONE)
		{
			printf("Failed to Convert time: %s (%u)", IEC61850_ErrorString(error), error);
		}
		else
		{
			printf(" %02u/%02u/%u %02u:%02u:%02u \n", myDateTime.month, myDateTime.tm_mday, myDateTime.year, myDateTime.tm_hour, myDateTime.tm_min, myDateTime.tm_sec);
		}
	\endcode
*/
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetDateFromIEC61850Time(struct IEC61850_DateTime * outDateTime, const struct IEC61850_TimeStamp * inTimestamp);

/*!	\brief 		An API For the stack in client mode to set the orCat value and OrIdent for an individual control if a DAID is specified
				OR if NULL then the orCat value specified should be set for ALL Controls

	\ingroup 		Control

	\param[in] 		client					IEC61850 Client object
	\param[in]		ptControlID				The ID of the control to set, or NULL to set for all controls
	\param[in]		OrCatValue				The Originator Category Value of type enum eOriginatorCat
	\param[in]		ptOrIdentData			The Originator identification Value of Maximum 64 characters, can be NULL if u8NewOrIdentSize is 0, this will use the current value of the Orident, default is the local IP address
	\param[in]		u8NewOrIdentSize        The Originator identification string Size in Bytes

	\return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	Example Usage:
	\code
		enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
		enum eOriginatorCat OrCatValue;
		struct IEC61850_DataAttributeID_Generic CtrlDAID;

		// Setup the Data Attribute ID (DAID) Struct - We set this to the CtlVal of the Control
		CtrlDAID.Generic_type = IEC61850_DAID_GENERIC;
		CtrlDAID.uiField1 = 2;
		CtrlDAID.uiField2 = 1;
		CtrlDAID.uiField3 = 0;
		CtrlDAID.uiField4 = 0;
		CtrlDAID.uiField5 = 0;

		//Set the Originator Identification as IP address
		char ptOrIdentData[] = "192.168.1.100";

		//Set the size of the OrIdent String
		u8NewOrIdentSize = 13;

		// Set the OrCatValue for Selected Control or if DAID is Null then For all the Controls
		OrCatValue = ORCAT_BAY_CONTROL;

		//Call the API to set the OrCat Value for specified Control DAIA
		eErrorCode = IEC61850_SetOriginator(myIEC61850ClientObject, (struct IEC61850_DataAttributeID*)&CtrlDAID, OrCatValue,ptOrIdentData, u8NewOrIdentSize );

		if(eErrorCode == IEC61850_ERROR_NONE)
		{
			printf("OrCat and OrIdent set Successfully\n");
		}
		else
		{
			printf("Set OrCat and OrIdent Value failed:%i: %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode));
		}
	\endcode
*/
PIS10_API enum IEC61850_ErrorCodes IEC61850_SetOriginator(IEC61850 client, struct IEC61850_DataAttributeID * ptControlID, enum eOriginatorCat OrCatValue, char * ptOrIdentData, Unsigned8 u8NewOrIdentSize);

/*!  \brief 		Get a list of remote MMS connections to the IEC 61850 Stack including MMS index and details
	 \ingroup 		Support

	 \param[in] 	clientServer			Client or Server object to read from
	 \param[out] 	ptRemoteConnectionsList	Pointer to a ConnectionsList structure pointer that will be modified to point to the generated list, or be made NULL if no connections are present

	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	 \details       NOTE: remoteConnectionList->ptConnectedServers[u32Count].ptDomainName will be an empty c string "" if the PIS10 is in server mode

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
		struct ConnectionsList *remoteConnectionList = NULL; //create a structure pointer for the remote connection List

		// Request the list from the server, passing in a pointer to the above pointer.
		error = IEC61850_GetConnectionsList(myIEC61850Object, &remoteConnectionList);
		if(error == IEC61850_ERROR_NONE)
		{
			if((remoteConnectionList != NULL) && (remoteConnectionList->u16NumberOfConnectedServers > 0))
			{
				// Print the list
				printf("\n\tConnected Servers (%u):\n", remoteConnectionList->u16NumberOfConnectedServers);
				printf("\tIndex\tDomain Name\t\tIP Address\tConnection Status\n");
				for(u32Count = 0; u32Count < remoteConnectionList->u16NumberOfConnectedServers; u32Count++)
				{
					printf("\t%u\t%s\t%s\t%s\n",
						remoteConnectionList->ptConnectedServers[u32Count].uiAAIndex,
						remoteConnectionList->ptConnectedServers[u32Count].ptDomainName,
						remoteConnectionList->ptConnectedServers[u32Count].ptIPAddress,
						remoteConnectionList->ptConnectedServers[u32Count].bConnectionState ? "Connected" : "Disconnected"); //status 2 is connected
				}
			}
			else
			{
				printf("\n\t No remote connections present\n");
			}
		}
		else
		{
			printf(strError, SIZE_OF_ERROR_STRING, "Get Connections list failed: %i: %s\n", error, IEC61850_ErrorString(error)==NULL?"MMS Error":IEC61850_ErrorString(error));
		}
	\endcode
 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetConnectionsList(IEC61850 clientServer, struct ConnectionsList ** ptRemoteConnectionsList);






/*!  \brief 		Returns file or directory attributes from a connected MMS server
	 \ingroup 		FileTransfer

	 \param[in] 	client				Client object to read from
	 \param[in] 	uiServerIndex		Connected server index
	 \param[in] 	filename           	The file or directory name to read.
	 \param[in] 	continueAfter      	Filename to continue after in a directory listing. NULL if none.
	 \param[out]	ptFileAttributes	Pointer to a structure containing the file name or directory required and which will be populated with the returned data

	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	 \see			IEC61850_DestroyFileAttributeValues()

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
		struct tFileAttr tFileAttributes;

		error = IEC61850_GetFileAttributeValues(myIEC61850Object, connectedServerIndex, "/path/to/directory", NULL, &tFileAttributes);
		if(error != IEC61850_ERROR_NONE)
		{
			printf("Get file attributes failed: %i: %s\n", error, IEC61850_ErrorString(error)==NULL?"MMS Error":IEC61850_ErrorString(error));
		}
		else
		{
			// Print list of files and attributes
			Unsigned32 fileCount = 0;
			printf("Received attributes for %u file(s):\n", tFileAttributes.u32NumOfDirectoryEntries);
			printf("\tFile\tTime Stamp\tSize [Bytes]\tFile Name\n");
			for(fileCount = 0; fileCount < tFileAttributes.u32NumOfDirectoryEntries; fileCount++)
			{
				printf("\t%d:\t%s\t%u\t\t%s\n", fileCount + 1, tFileAttributes.ptArrayofDirectoryEntries[fileCount].ctLastModified, tFileAttributes.ptArrayofDirectoryEntries[fileCount].u32FileSize, tFileAttributes.ptArrayofDirectoryEntries[fileCount].cFileName);
			}
			IEC61850_DestroyFileAttributeValues(&tFileAttributes);
		}
	\endcode
 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetFileAttributeValues(IEC61850 client, unsigned int uiServerIndex, const char* filename, const char* continueAfter, struct tFileAttr* ptFileAttributes);



/*!  \brief 		Frees memory associated with the file attributes returned by IEC61850_GetFileAttributeValues()
	 \ingroup 		FileTransfer

	 \param[in] 	ptFileAttributes			The file attributes to destroy after a IEC61850_GetFileAttributeValues() call.

	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure
	 
	 \see			IEC61850_GetFileAttributeValues()

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
		struct tFileAttr tFileAttributes;

		error = IEC61850_GetFileAttributeValues(myIEC61850Object, 0, "/path/to/directory", NULL, &tFileAttributes);
		if(error != IEC61850_ERROR_NONE)
		{
			printf("Get file attributes failed: %i: %s\n", error, IEC61850_ErrorString(error)==NULL?"MMS Error":IEC61850_ErrorString(error));
		}
		else
		{
			// Print list of files and attributes
			Unsigned32 fileCount = 0;
			printf("Received attributes for %u file(s):\n", ptFileAttributes.u32NumOfDirectoryEntries);
			printf("\tFile\tTime Stamp\tSize [Bytes]\tFile Name\n");
			for(fileCount = 0; fileCount < tFileAttributes.u32NumOfDirectoryEntries; fileCount++)
			{
				printf("\t%d:\t%s\t%u\t\t%s\n", fileCount + 1, tFileAttributes.ptArrayofDirectoryEntries[fileCount].ctLastModified, tFileAttributes.ptArrayofDirectoryEntries[fileCount].u32FileSize, tFileAttributes.ptArrayofDirectoryEntries[fileCount].cFileName);
			}
			IEC61850_DestroyFileAttributeValues(&tFileAttributes);
		}
	\endcode
 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_DestroyFileAttributeValues(struct tFileAttr* ptFileAttributes);


/*!  \brief 		Initiates sending a file from this client to a connected MMS server, this is an asynchronous / nonblocking API function
					#IEC61850_FileCallback will be called with code IEC61850_FILE_CALL_READ when the server replies with a request the file from the client starting the actual transfer - This is due to how SetFile works over MMS where the server actually Reads the file from the client
					#IEC61850_FileCallback will be called with code IEC61850_FILE_CALL_SET_FILE_COMPLETE when the set file transfer is completed
					#IEC61850_FileCallback will be called with code IEC61850_FILE_CALL_SET_FILE_FAIL if an error occurs 

	 \ingroup 		FileTransfer

	 \param[in] 	client			client object to access transaction 
	 \param[in] 	uiServerIndex	connected server index
	 \param[in] 	pRemoteFileName	the remote destination file name that the server will write the file too
	 \param[in] 	pLocalFileName	the local source file name

	 \return 		#IEC61850_ERROR_NONE on success of sending the SetFile Request or error code from enum #IEC61850_ErrorCodes on failure

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;

		error = IEC61850_SetFile(myServer, connectedServerIndex, "IED1.cid", "MyFiles\IED1.cid");
		if(error != IEC61850_ERROR_NONE)
		{
			printf("Set File failed: %i: %s\n", error, IEC61850_ErrorString(error)==NULL?"MMS Error":IEC61850_ErrorString(error));
		}
		else
		{
			printf("Success\n");
		}


		// Client side File Callback example for SetFile
		enum IEC61850_FileResponseCode FileCallbackHandler(void * ptUserData, enum IEC61850_FileCallType fileCallType, struct tFileAttr* ptFileAttributes)
		{
			enum IEC61850_FileResponseCode responseCode = IEC61850_FILE_RESPONSE_ACCEPT;

			switch(fileCallType)
			{
				case IEC61850_FILE_CALL_READ:	//This File is being obtained by the server from the client
					printf("local file being sent to server: %s\n", ptFileAttributes->primaryFile.cFileName);
					//Only allow IED1.cid to be obtained by the client
					if(strcmp(ptFileAttributes->primaryFile.cFileName, "MyFiles\IED1.cid") == 0)
					{
						responseCode = IEC61850_FILE_RESPONSE_ACCEPT;
					}
					else
					{
						responseCode = IEC61850_FILE_RESPONSE_ACCESS_DENIED;
					}
					break;
				case IEC61850_FILE_CALL_SET_FILE_COMPLETE:	//!< Set File transfer is complete.	Callback: The primary file is the local file, and the directory entries list contains the remote filename
					printf("Set file from completed successfully. Local file '%s', bytes written to disk '%u'\n", ptFileAttributes->primaryFile.cFileName, ptFileAttributes->primaryFile.u32FileSize);
					break;
				case IEC61850_FILE_CALL_SET_FILE_FAIL:	//!< Set File Transfer has Failed - Partial file may be on the file system.  Callback: The primary file is the local file, and the directory entries list contains the remote filename
					printf("Set file from FAILED. Local file '%s', bytes written to disk '%u'\n", ptFileAttributes->primaryFile.cFileName, ptFileAttributes->primaryFile.u32FileSize);
					break;
				default:
					printf("Unknown file call type %d\n", fileCallType);
					break;
			}

			return responseCode;
		}

	\endcode
 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_SetFile(IEC61850 client, unsigned int uiServerIndex, const char* pRemoteFileName, const char* pLocalFileName);

/*!  \brief 		Copy a file from a connected MMS server to a local destination
	 \ingroup 		FileTransfer

	 \param[in] 	client			Client object to read from
	 \param[in] 	uiServerIndex	connected server index
	 \param[in] 	pRemoteFileName	Pointer to a char array containing the file name
	 \param[in] 	pLocalFileName	Pointer to a char array containing the local destination file name

	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;

		error = IEC61850_GetFile(myServer, connectedServerIndex, "IED1.cid", "IED1.cid");
		if(error != IEC61850_ERROR_NONE)
		{
			printf("Get File failed: %i: %s\n", error, IEC61850_ErrorString(error)==NULL?"MMS Error":IEC61850_ErrorString(error));
		}
		else
		{
			printf("Success\n");
		}
	\endcode
 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetFile(IEC61850 client, unsigned int uiServerIndex, const char * pRemoteFileName, const char * pLocalFileName);



/*!  \brief 		Delete a file from a connected MMS server
	 \ingroup 		FileTransfer

	 \param[in] 	client				Client object to read from
	 \param[in] 	uiServerIndex		connected server index
	 \param[in] 	pFileNameToDelete	Pointer to a char array containing the file name to delete

	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	Example Usage:
	\code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;

		error = IEC61850_DeleteFile(myServer, connectedServerIndex, "oldLogFile.txt");
		if(error != IEC61850_ERROR_NONE)
		{
			printf("Delete File failed: %i: %s\n", error, IEC61850_ErrorString(error)==NULL?"MMS Error":IEC61850_ErrorString(error));
		}
		else
		{
			printf("Success\n");
		}
	\endcode
 */
PIS10_API enum IEC61850_ErrorCodes IEC61850_DeleteFile(IEC61850 client, unsigned int uiServerIndex, const char * pFileNameToDelete);

/*!	 \brief 	Get the Data Attribute Data structure and value for a given Data Attribute ID from the internal database
	 \ingroup 	DataAttributeAccess

	 \param[in] 	inServer		Client or Server object to search
	 \param[in] 	inDAID			Pointer to the Data Attribute ID of the Data Attribute to be found
	 \param[out] 	outReturnValue	Pointer to a valid Data Attribute Data struct to store the details of the data point that is stored inside the PIS10 Database. ** Please Note that the pvData pointer is a live pointer and the associated value should not be changed **

	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure
*/
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetDataAttributeData(IEC61850 inServer, struct IEC61850_DataAttributeID * inDAID, struct IEC61850_DataAttributeData * outReturnValue);



/*!	 \brief 	Get the MMS dollar($) string for a given Data Attribute ID,

	 \ingroup 	DataAttributeAccess

	 \param[in] 	inServer		Client or Server object to search
	 \param[in] 	inDAID			Pointer to the Data Attribute ID of the Data Attribute to be found
	 \param[out] 	OutMMSString	Pointer to a c string (char array) that will store the string, must be at least 130 bytes long and will be null-terminated.

	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure
*/
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetMMSStringForPrivateID(IEC61850 inServer, struct IEC61850_DataAttributeID * inDAID, char * OutMMSString);

/*!	 \brief 	Get the Data Attribute ID for a given MMS dollar($) string, This function will only work on a server IEC61850 object

	 \ingroup 	DataAttributeAccess

	 \param[in] 	inServer		Client or Server object to search
	 \param[in] 	inMMSString		pointer to the MMS Dollar string, must contain the domain
	 \param[out] 	outDAID		Pointer to a struct IEC61850_DataAttributeID to hold the Data Attribute ID

	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure
*/
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetPrivateIDForMMSString(IEC61850 inServer, const char * inMMSString,  struct IEC61850_DataAttributeID * outDAID);

/*!	 \brief 	Builds an array for each goose control block that includes the GooSE control block reference, publisher or subscriber flag, is enabled and the Data Attribute IDs of each DataSet item

	 \ingroup 	DataAttributeAccess

	 \param[in] 	inServer		Client or Server object to search
	 \param[in] 	outGOOSECBArray		An pointer that will have an array allocated to it that will hold the goose control block data
	 \param[out] 	outGOOSECBArraySize	 the size (number of elements) of the outGOOSECBArray

	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure
	 
	 example usage:
	 \code
	 enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
	 struct GOOSEControlBlocks *outGOOSECBArray = NULL;
	 Unsigned32 outGOOSECBArraySize =0;
	 Unsigned32 i =0;

	 error = IEC61850_GetGOOSEControlBlockInfo(myIEC61850Object, &outGOOSECBArray,  &outGOOSECBArraySize);
	 
	 printf("Number of GOOSE Control Blocks %d \n",outGOOSECBArraySize );
	 
	 for(i=0; i<outGOOSECBArraySize; i++)
	 {
		printf("Goose CB %d = %s\n",i ,outGOOSECBArray[i].ptGoCBRef);
	 }

	 //once finished free the DAIDArrays in each GOOSE CB element
	 for(i=0; i<outGOOSECBArraySize; i++)
	 {
		free(outGOOSECBArray->ptDAIDArray);
	 }

	 //Free the GOOSECBArray
	 free(outGOOSECBArray);
	 
	 \endcode
*/
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetGOOSEControlBlockInfo(IEC61850 inServer, struct GOOSEControlBlocks ** outGOOSECBArray, Unsigned32 *outGOOSECBArraySize);





/*!	 \brief 	Populates an array that will contain information of data attributes (DA) that have been assigned a private ID in the SCL file
				The outDataAttributeInfoArr array will be populated with information of data attributes from an internal array, this will happen in a sequential manner. 
				the outDataAttributeInfoArr array will be populated until outArrSize is reached or there are no more Data Attributes to fill. 
				The inContinueAfter value can be used to continue populating the outDataAttributeInfoArr from an index of the internal array, this allows to get DAInfo in blocks
				<br>
				If outDataAttributeInfoArr is passed in as NULL then outArrSize will be populated with the total number of Data Attributes with Private IDs available in the loaded SCL file. 		

	 \ingroup 	DataAttributeAccess

	 \param[in]		inServerClient			Client or Server object to search
	 \param[out] 	outDataPointInfoArr		An pointer that will has an array allocated to it that will hold the data attribute info, if NULL outArrSize will be set to the max number of Data Attributes available 
	 \param[in,out] 	outArrSize			the size (number of elements) of the outDataPointInfoArr, this will be over written with the number of DAs stored in the outDataAttributeInfoArr
	 \param[in] 	startAt		The index of the internal array to start getting data attributes, indexed from 0.

	 \return 		#IEC61850_ERROR_NONE on success or error code from enum #IEC61850_ErrorCodes on failure

	 example usage:
	 \code
		enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
		struct DAInfo dataPointInfoArr[50] = { 0 };
		Unsigned32 totalDataPoints = 0;
		Unsigned32 daArrSize = 0;
		Unsigned32 continueAfter = 0;
		Unsigned32 i = 0;

		error = IEC61850_GetDataAttributesInfo(GetMyServerClient(inServerClientIndex), NULL, &totalDataPoints, 0);

		printf("Number of Data attributes %u \n", totalDataPoints);

		while (continueAfter < totalDataPoints)
		{
			daArrSize = 50;

			IEC61850_GetDataAttributesInfo(GetMyServerClient(inServerClientIndex), dataPointInfoArr, &daArrSize, continueAfter);

			continueAfter += daArrSize;

			for (i = 0; i < daArrSize; i++)
			{
				//Print Item Name
				printf("Name: %s\n", dataPointInfoArr[i].name);
				IEC61850_PrintDataAttributeID(dataPointInfoArr[i].DAID);
				printf("\n");
			}
		}

	 \endcode
*/
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetDataAttributesInfo(IEC61850 inServerClient, struct DAInfo * outDataPointInfoArr, Unsigned32  *outArrSize, Unsigned32 startAt);
/*!	 \brief 	Query log by time specifies a given log and start and stop time range of which all log entries between these times will be returned.

	 \ingroup 	log

	 \param[in] 	client		         the IEC61850 struct passed into all API calls
	 \param[in] 	CBID		         The Control Block ID that references a specific
	 \param[in] 	startTime            The start range of the log entries to get, or NULL No limit on start time
	 \param[in] 	stopTime             The stop range of the log entries to get, or NULL No limit on stop time
	 \param[out] 	returnedLogEntries   A pointer to a LogEntries Structure to store the results, but the data inside should be NULL as the stack will allocate these pointers.

	 \return 		IEC61850_ERROR_NONE on success
	 \return 		otherwise error code
	 
	 example usage:
	 \code
	 enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
	 
	 struct IEC61850_TimeStamp startTime = { 0 };
	 struct IEC61850_TimeStamp stopTime = { 0 };
	 struct IEC61850_LogEntries returnedLogEntries;
	 eErrorCode = IEC61850_GetIEC61850TimeFromDate(&startTime, 2, 25, 2019, 0, 0, 0, 0);
	 eErrorCode = IEC61850_GetIEC61850TimeFromDate(&stopTime, 3, 2, 2019, 12, 13, 11, 0);
	 
	 struct IEC61850_ControlBlockID CBID = { 0 };
	 CBID.controlBlockType = CONTROLBLOCK_LOG;
	 CBID.uiField1 = 2;
	 CBID.uiField2 = 2;
	 CBID.uiField3 = 2;
	 CBID.uiField4 = 1;
	 eErrorCode = IEC61850_QueryLogByTime(GetMyServerClient(), &CBID, &startTime, &stopTime, &returnedLogEntries);
	 //if No limit on start time and stop time
	 eErrorCode = IEC61850_QueryLogByTime(GetMyServerClient(), &CBID, NULL, NULL, &returnedLogEntries);
	 
	 \endcode
*/
PIS10_API enum IEC61850_ErrorCodes IEC61850_QueryLogByTime(IEC61850 client, unsigned int uiServerIndex, char* logRef, struct IEC61850_TimeStamp * startTime, struct IEC61850_TimeStamp * stopTime, struct IEC61850_LogEntries * returnedLogEntries);

/*!	 \brief 	Query log by time specifies a given log, a time stamp and an entry ID of which all log entries after both of these values will be returned.

	 \ingroup 	log

	 \param[in] 	client		         the IEC61850 struct passed into all API calls
	 \param[in] 	CBID		         The Control Block ID that references a specific
	 \param[in] 	startTime            The starting timestamp of the log entries to get
	 \param[in] 	entryID              The starting EntryID of the log entries to get
	 \param[out] 	returnedLogEntries   A pointer to a LogEntries Structure to store the results, but the data inside should be NULL as the stack will allocate these pointers.

	 \return 		IEC61850_ERROR_NONE on success
	 \return 		otherwise error code
	 
	 example usage:
	 \code
	 enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
	 Unsigned32 u32EntryID  = 123;
	 struct IEC61850_TimeStamp startTime = { 0 };
	 struct IEC61850_LogEntries returnedLogEntries;
	 eErrorCode = IEC61850_GetIEC61850TimeFromDate(&startTime, 2, 25, 2019, 0, 0, 0, 0);

	 
	 struct IEC61850_ControlBlockID CBID = { 0 };
	 CBID.controlBlockType = CONTROLBLOCK_LOG;
	 CBID.uiField1 = 2;
	 CBID.uiField2 = 2;
	 CBID.uiField3 = 2;
	 CBID.uiField4 = 1;
	 eErrorCode = IEC61850_QueryLogAfter(GetMyServerClient(), &CBID, &startTime, u32EntryID, &returnedLogEntries);
	 
	 \endcode
*/

PIS10_API enum IEC61850_ErrorCodes IEC61850_QueryLogAfter(IEC61850 client, unsigned int uiServerIndex, char* logRef, struct IEC61850_TimeStamp * startTime, Unsigned32 , struct IEC61850_LogEntries * returnedLogEntries);
/*!	 \brief 	Get Log Status Values gets the Oldest and Newest EntryID and Entry time stamp values

	 \ingroup 	log

	 \param[in] 	client		         the IEC61850 struct passed into all API calls
	 \param[in] 	CBID		         The Control Block ID that references a specific
	 \param[out] 	returnedLogStatus    A pointer to a LogStatus Structure to store the results

	 \return 		IEC61850_ERROR_NONE on success
	 \return 		otherwise error code
	 
	 example usage:
	 \code
	 enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
	 struct IEC61850_LogStatus  returnedLogStatus = { 0 };
	 
	 struct IEC61850_ControlBlockID CBID = { 0 };
	 CBID.controlBlockType = CONTROLBLOCK_LOG;
	 CBID.uiField1 = 2;
	 CBID.uiField2 = 2;
	 CBID.uiField3 = 2;
	 CBID.uiField4 = 1;
	 eErrorCode = IEC61850_GetLogStatusValues(GetMyServerClient(), &CBID, &returnedLogStatus);
	 
	 \endcode
*/

PIS10_API enum IEC61850_ErrorCodes IEC61850_GetLogStatusValues(IEC61850 client, unsigned int uiServerIndex, char* sLDName, char* sLogName, struct IEC61850_LogStatus * returnedLogStatus);


/*!	 \brief 	free struct IEC61850_LogEntries

	 \ingroup 	log

	 \param[in] 	ptLog		         the point of struct IEC61850_LogEntries

	 \return 		IEC61850_ERROR_NONE on success
	 \return 		otherwise error code
	 
	 example usage:
	 \code
	 enum IEC61850_ErrorCodes error = IEC61850_ERROR_NONE;
	 Unsigned32 u32EntryID  = 123;
	 struct IEC61850_TimeStamp startTime = { 0 };
	 struct IEC61850_LogEntries returnedLogEntries;
	 eErrorCode = IEC61850_GetIEC61850TimeFromDate(&startTime, 2, 25, 2019, 0, 0, 0, 0);

	 
	 struct IEC61850_ControlBlockID CBID = { 0 };
	 CBID.controlBlockType = CONTROLBLOCK_LOG;
	 CBID.uiField1 = 2;
	 CBID.uiField2 = 2;
	 CBID.uiField3 = 2;
	 CBID.uiField4 = 1;
	 eErrorCode = IEC61850_QueryLogAfter(GetMyServerClient(), &CBID, &startTime, u32EntryID, &returnedLogEntries);
	 if(eErrorCode == IEC61850_ERROR_NONE)
	 {
	     //Add the use of returnedLogEntries here

	     //Make sure you are no longer using returnedLogEntries
	     eErrorCode = IEC61850_FreeLogEntries(&returnedLogEntries);
	 }

	 
	 \endcode
*/
//PIS10_API enum IEC61850_ErrorCodes IEC61850_UpdateReportDatas(IEC61850 clientServer, struct IEC61850_ControlBlockID* ptCBID, struct IEC61850_DataAttributeData* ptDatas, unsigned int uiDatasNum);
PIS10_API enum IEC61850_ErrorCodes IEC61850_ReadDirect(IEC61850 client, unsigned int uiServerIndex, char* Domain, char* Item, struct tMmsDataItem* ptDataToBeRead, unsigned int uiCount);
PIS10_API enum IEC61850_ErrorCodes IEC61850_WriteDirect(IEC61850 client, unsigned int uiServerIndex, char* Domain, char* Item, struct tMmsDataItem* ptDataToBeWritten);
PIS10_API enum IEC61850_ErrorCodes IEC61850_FreeLogEntries(struct IEC61850_LogEntries * ptLog);
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetDataSetDirectory(IEC61850 client, unsigned int uiServerIndex, char* ItemName, char* DomainName, struct StringList* ptDataSetRefList);
PIS10_API enum IEC61850_ErrorCodes IEC61850_GetReportDataArray(IEC61850 clientServer, struct IEC61850_ControlBlockID* ptCBID, unsigned int 	uiReportInstanceIndex, struct IEC61850_DataAttributeData** ptDataAttributeDatas, unsigned int* pDatasNumber);
PIS10_API enum IEC61850_ErrorCodes IEC61850_UpdateReportDatas(IEC61850 clientServer, struct IEC61850_ControlBlockID* ptCBID, unsigned int 	uiReportInstanceIndex, struct IEC61850_DataAttributeData* ptDataAttributeDatas, unsigned int uiDatasNum, enum eReportSendDataReasonCode eRptReason);

PIS10_API struct StringList* StringListMalloc();
PIS10_API int StringListAdd(struct StringList* strlist, char* str);
PIS10_API int StringListAddNew(struct StringList* strlist, char* str);
PIS10_API void FreeStringList(struct StringList* pList);


#ifdef __cplusplus
}
#endif

#endif
